# -*- coding: utf-8 -*-
"""
周期因子分析预测申购和赎回金额 - 改进版本
使用weekday和day周期因子进行预测
"""

import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')

def setup_encoding():
    """设置控制台编码，解决中文乱码问题"""
    import sys
    import os
    if sys.platform.startswith('win'):
        os.system('chcp 65001 > nul')
        sys.stdout.reconfigure(encoding='utf-8')
        sys.stderr.reconfigure(encoding='utf-8')

def load_and_preprocess_data():
    """
    加载和预处理数据
    筛选2014-03-01到2014-08-31的数据
    """
    print("正在加载数据...")
    
    # 读取数据
    df = pd.read_csv('user_balance_table.csv')
    
    # 转换日期格式
    df['report_date'] = pd.to_datetime(df['report_date'], format='%Y%m%d')
    
    # 筛选2014-03-01到2014-08-31的数据
    start_date = pd.to_datetime('2014-03-01')
    end_date = pd.to_datetime('2014-08-31')
    
    df_filtered = df[(df['report_date'] >= start_date) & (df['report_date'] <= end_date)].copy()
    
    print(f"筛选后数据量: {len(df_filtered)} 条记录")
    print(f"日期范围: {df_filtered['report_date'].min()} 到 {df_filtered['report_date'].max()}")
    
    return df_filtered

def aggregate_daily_data(df):
    """
    按日期聚合申购和赎回金额
    """
    print("正在按日期聚合数据...")
    
    # 按日期聚合
    daily_data = df.groupby('report_date').agg({
        'total_purchase_amt': 'sum',
        'total_redeem_amt': 'sum'
    }).reset_index()
    
    # 提取时间特征
    daily_data['weekday'] = daily_data['report_date'].dt.dayofweek  # 0-6 (周一到周日)
    daily_data['day'] = daily_data['report_date'].dt.day  # 1-31
    daily_data['month'] = daily_data['report_date'].dt.month
    
    print(f"聚合后数据量: {len(daily_data)} 天")
    print(f"申购总金额: {daily_data['total_purchase_amt'].sum():.2f}")
    print(f"赎回总金额: {daily_data['total_redeem_amt'].sum():.2f}")
    
    return daily_data

def calculate_weekday_factors(daily_data):
    """
    计算Weekday周期因子
    计算一周中每天的平均申购/赎回量，然后除以总体平均值
    """
    print("正在计算Weekday周期因子...")
    
    # 计算总体平均值
    overall_purchase_mean = daily_data['total_purchase_amt'].mean()
    overall_redeem_mean = daily_data['total_redeem_amt'].mean()
    
    print(f"总体申购平均值: {overall_purchase_mean:.2f}")
    print(f"总体赎回平均值: {overall_redeem_mean:.2f}")
    
    # 按weekday分组计算平均值
    weekday_stats = daily_data.groupby('weekday').agg({
        'total_purchase_amt': 'mean',
        'total_redeem_amt': 'mean'
    }).reset_index()
    
    # 计算周期因子（每天平均值 / 总体平均值）
    weekday_stats['purchase_factor'] = weekday_stats['total_purchase_amt'] / overall_purchase_mean
    weekday_stats['redeem_factor'] = weekday_stats['total_redeem_amt'] / overall_redeem_mean
    
    # 创建字典便于查找
    weekday_purchase_factors = dict(zip(weekday_stats['weekday'], weekday_stats['purchase_factor']))
    weekday_redeem_factors = dict(zip(weekday_stats['weekday'], weekday_stats['redeem_factor']))
    
    print("\nWeekday周期因子:")
    weekday_names = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
    for i, row in weekday_stats.iterrows():
        print(f"{weekday_names[int(row['weekday'])]} (weekday={int(row['weekday'])}): "
              f"申购因子={row['purchase_factor']:.4f}, 赎回因子={row['redeem_factor']:.4f}")
    
    return weekday_purchase_factors, weekday_redeem_factors

def calculate_day_factors(daily_data):
    """
    计算Day周期因子
    计算一个月中每天的平均申购/赎回量，然后除以总体平均值
    """
    print("\n正在计算Day周期因子...")
    
    # 计算总体平均值
    overall_purchase_mean = daily_data['total_purchase_amt'].mean()
    overall_redeem_mean = daily_data['total_redeem_amt'].mean()
    
    # 按day分组计算平均值
    day_stats = daily_data.groupby('day').agg({
        'total_purchase_amt': 'mean',
        'total_redeem_amt': 'mean'
    }).reset_index()
    
    # 计算周期因子（每天平均值 / 总体平均值）
    day_stats['purchase_factor'] = day_stats['total_purchase_amt'] / overall_purchase_mean
    day_stats['redeem_factor'] = day_stats['total_redeem_amt'] / overall_redeem_mean
    
    # 创建字典便于查找
    day_purchase_factors = dict(zip(day_stats['day'], day_stats['purchase_factor']))
    day_redeem_factors = dict(zip(day_stats['day'], day_stats['redeem_factor']))
    
    print("\nDay周期因子 (前10天):")
    for i in range(1, 11):
        if i in day_purchase_factors:
            print(f"第{i}天: 申购因子={day_purchase_factors[i]:.4f}, 赎回因子={day_redeem_factors[i]:.4f}")
    
    print(f"... (共{len(day_purchase_factors)}天的因子)")
    
    return day_purchase_factors, day_redeem_factors

def generate_september_predictions(weekday_purchase_factors, weekday_redeem_factors,
                                 day_purchase_factors, day_redeem_factors,
                                 overall_purchase_mean, overall_redeem_mean):
    """
    生成2014年9月的预测
    对每一天应用对应的weekday和day周期因子
    """
    print("\n正在生成2014年9月预测...")
    
    # 生成2014年9月的所有日期
    start_date = datetime(2014, 9, 1)
    end_date = datetime(2014, 9, 30)
    
    predictions = []
    current_date = start_date
    
    while current_date <= end_date:
        weekday = current_date.weekday()  # 0-6
        day = current_date.day  # 1-31
        
        # 获取对应的周期因子
        weekday_purchase_factor = weekday_purchase_factors.get(weekday, 1.0)
        weekday_redeem_factor = weekday_redeem_factors.get(weekday, 1.0)
        day_purchase_factor = day_purchase_factors.get(day, 1.0)
        day_redeem_factor = day_redeem_factors.get(day, 1.0)
        
        # 结合两个因子（相乘）
        combined_purchase_factor = weekday_purchase_factor * day_purchase_factor
        combined_redeem_factor = weekday_redeem_factor * day_redeem_factor

        # combined_purchase_factor = weekday_purchase_factor
        # combined_redeem_factor = weekday_redeem_factor 
        # 计算预测值
        predicted_purchase = overall_purchase_mean * combined_purchase_factor
        predicted_redeem = overall_redeem_mean * combined_redeem_factor
        
        predictions.append({
            'report_date': current_date.strftime('%Y%m%d'),
            'purchase': predicted_purchase,
            'redeem': predicted_redeem,
            'weekday': weekday,
            'day': day,
            'weekday_purchase_factor': weekday_purchase_factor,
            'weekday_redeem_factor': weekday_redeem_factor,
            'day_purchase_factor': day_purchase_factor,
            'day_redeem_factor': day_redeem_factor,
            'combined_purchase_factor': combined_purchase_factor,
            'combined_redeem_factor': combined_redeem_factor
        })
        
        current_date += timedelta(days=1)
    
    pred_df = pd.DataFrame(predictions)
    
    print(f"生成了 {len(pred_df)} 天的预测")
    print(f"预测申购总金额: {pred_df['purchase'].sum():.2f}")
    print(f"预测赎回总金额: {pred_df['redeem'].sum():.2f}")
    
    return pred_df

def save_results(pred_df):
    """
    保存预测结果到factor_result3.csv
    """
    print("\n正在保存结果...")
    
    # 选择需要的列
    result_df = pred_df[['report_date', 'purchase', 'redeem']].copy()
    
    # 保存到CSV文件
    result_df.to_csv('factor_result3.csv', index=False, encoding='utf-8')
    
    print("结果已保存到 factor_result3.csv")
    print("\n预测结果预览:")
    print(result_df.head(10))
    
    return result_df

def analyze_factors(pred_df):
    """
    分析周期因子的效果
    """
    print("\n" + "="*60)
    print("周期因子分析")
    print("="*60)
    
    # 按星期几分析
    weekday_analysis = pred_df.groupby('weekday').agg({
        'purchase': 'mean',
        'redeem': 'mean',
        'combined_purchase_factor': 'mean',
        'combined_redeem_factor': 'mean'
    }).round(4)
    
    print("\n按星期几的预测分析:")
    weekday_names = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
    for i in range(7):
        if i in weekday_analysis.index:
            row = weekday_analysis.loc[i]
            print(f"{weekday_names[i]}: 申购={row['purchase']:.0f}, 赎回={row['redeem']:.0f}, "
                  f"申购因子={row['combined_purchase_factor']:.4f}, 赎回因子={row['combined_redeem_factor']:.4f}")
    
    # 按日期分析
    print("\n按日期的预测分析 (前10天):")
    for i in range(1, 11):
        day_data = pred_df[pred_df['day'] == i]
        if not day_data.empty:
            row = day_data.iloc[0]
            print(f"第{i}天: 申购={row['purchase']:.0f}, 赎回={row['redeem']:.0f}, "
                  f"申购因子={row['combined_purchase_factor']:.4f}, 赎回因子={row['combined_redeem_factor']:.4f}")

def main():
    """主函数"""
    # 设置编码
    setup_encoding()
    
    print("=" * 60)
    print("周期因子分析预测申购和赎回金额 - 改进版本")
    print("=" * 60)
    
    try:
        # 1. 加载和预处理数据
        df = load_and_preprocess_data()
        
        # 2. 按日期聚合数据
        daily_data = aggregate_daily_data(df)
        
        # 3. 计算总体平均值
        overall_purchase_mean = daily_data['total_purchase_amt'].mean()
        overall_redeem_mean = daily_data['total_redeem_amt'].mean()
        
        # 4. 计算Weekday周期因子
        weekday_purchase_factors, weekday_redeem_factors = calculate_weekday_factors(daily_data)
        
        # 5. 计算Day周期因子
        day_purchase_factors, day_redeem_factors = calculate_day_factors(daily_data)
        
        # 6. 生成2014年9月预测
        pred_df = generate_september_predictions(
            weekday_purchase_factors, weekday_redeem_factors,
            day_purchase_factors, day_redeem_factors,
            overall_purchase_mean, overall_redeem_mean
        )
        
        # 7. 保存结果
        result_df = save_results(pred_df)
        
        # 8. 分析周期因子效果
        analyze_factors(pred_df)
        
        print("\n" + "=" * 60)
        print("预测完成！")
        print("=" * 60)
        
    except Exception as e:
        print(f"程序执行出错: {e}")
        import traceback
        traceback.print_exc()

if __name__ == "__main__":
    main()
